//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ContactCheck.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <math.h>

#include <iostream>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace ContacCkeckSpace {
  
  bool EqualResidue (TNode <String>* residue, void* ref) {

    return (!strcmp(residue->Info()->Out(), ((String*)ref)->Out()))?true:false;

  }
  
  bool AlphResidue(String* residue, void* ref) {

    return (strcmp(residue->Out(), ((String*)ref)->Out()) < 0)?true:false;

  }
  
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ContactCheck::ContactCheck (): ligandInt(NULL),
                               domain(NULL),
                               ansgtronDistance (0),
                               hasContact(false) {
  
  this->residues = new TListE <String> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ContactCheck::ContactCheck (const ContactCheck& contactCheck) {
  
  this->ligandInt         = contactCheck.ligandInt;
  this->domain            = contactCheck.domain;
  this->ansgtronDistance  = contactCheck.ansgtronDistance;
  
  this->hasContact        = contactCheck.hasContact;  
  this->residues          = new TListE <String> (contactCheck.residues);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ContactCheck::ContactCheck (const ContactCheck* contactCheck) {
  
  this->ligandInt         = contactCheck->ligandInt;
  this->domain            = contactCheck->domain;
  this->ansgtronDistance  = contactCheck->ansgtronDistance;
  
  this->hasContact        = contactCheck->hasContact;
  this->residues          = new TListE <String> (contactCheck->residues);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ContactCheck::~ContactCheck () {
  
  if (this->residues) delete this->residues;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ContactCheck::LigandInt (Ligand* ligandInt) {
  
  if (ligandInt) this->ligandInt = ligandInt;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ContactCheck::Domain (PDBAtom* domain) {
  
  if (domain) this->domain = domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ContactCheck::AnsgtronDistance (double ansgtronDistance) {
  
  if (ansgtronDistance > 0) this->ansgtronDistance = ansgtronDistance;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ContactCheck::HasContact (bool hasContact) {
 
  this->hasContact = hasContact;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ContactCheck::Residues (TListE <String>* residues) {
  
  if (residues) *(this->residues) = *residues;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
Ligand* ContactCheck::LigandInt (void) {
  
  return this->ligandInt;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
PDBAtom* ContactCheck::Domain (void) {
  
  return this->domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ContactCheck::AnsgtronDistance (void) {
  
  return this->ansgtronDistance;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ContactCheck::HasContact (void) {
  
  return this->hasContact;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>*  ContactCheck::Residues (void) {
  
  return this->residues;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ContactCheck::CheckForContacts (void) {
  
  if (!this->ligandInt || !this->ligandInt->Records()->Length() ||
      !this->domain    || !this->domain->Records()->Length()    ||
      this->ansgtronDistance <= 0)
    return false;
  
  this->residues->Clear();
  this->hasContact = false;
  
  this->domain->Records()->SetInitial();
  while (this->domain->Records()->SetNext()) {
    
    AtomRecord* currentAtomRecord = this->domain->Records()->GetCurrent();
    
    this->ligandInt->Records()->SetInitial();
    while (this->ligandInt->Records()->SetNext()) {

      HetAtmRecord* currentHetAtmRecord = this->ligandInt->Records()->GetCurrent();
      
      double distance = sqrt( (pow(currentAtomRecord->X() - currentHetAtmRecord->X(), 2)) +
                              (pow(currentAtomRecord->Y() - currentHetAtmRecord->Y(), 2)) +
                              (pow(currentAtomRecord->Z() - currentHetAtmRecord->Z(), 2)));
      
      if (distance <= this->ansgtronDistance) {
       
        this->hasContact = true;
        
        String* newContact = new String (currentAtomRecord->Name());
        newContact->Add(currentAtomRecord->Number());
        
        String* searchContact = this->residues->FirstOcurrence(ContacCkeckSpace::EqualResidue, newContact);
        
        if (!searchContact) this->residues->Add(newContact);
        else                delete newContact;
        
        break;
        
      }
      
    }
    
  }
  
  //this->residues->QuickSortListByArray(ContacCkeckSpace::AlphResidue, NULL);
  
  return true;  
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ContactCheck ContactCheck::operator= (const ContactCheck& contactCheck) {
  
  this->ligandInt         = contactCheck.ligandInt;
  this->domain            = contactCheck.domain;
  this->ansgtronDistance  = contactCheck.ansgtronDistance;
  
  *(this->residues)       = *(contactCheck.residues);

  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//

